package com.ncmmall.mall.controller.securitys;

import com.ncmmall.application.securitys.logs.OperationLogApplication;
import com.feijin.commons.captcha.HttpCaptchaUtils;
import com.feijin.commons.captcha.InvalidGraphicCaptchaException;
import com.feijin.commons.securitys.MD5HashUtils;
import com.ncmmall.domain.security.user.WebUser;
import com.ncmmall.mall.controller.securitys.shiro.Securitys;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

/**
 * @author likaikai
 * 登录登出
 */
@Controller
public class AdminController {

    private final Logger logger = LoggerFactory.getLogger(AdminController.class);

    public static final int UNKNOWN_ACCOUT_ERROR_CODE = 1;
    public static final int LOCKED_ACCOUT_ERROR_CODE = 2;
    public static final int AUTHENTICATION_ERROR_CODE = 4;
    public static final int INVALID_CAPTCHA_ERROR_CODE = 8;
    public static final int OTHER_ERROR_CODE = 16;
    public static final int EMPTY_INFO = 18;
    public static final int USER_IS_NOT_EXIST_ERROR_CODE = 20;

    @Value("${web.domain}")
    private String webDomain;

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private OperationLogApplication logApplication;


    /**
     * 登录页面
     */
    @RequestMapping(value = "/login", method = GET)
    public String login() {
        return "/securitys/login";
    }


    /**
     * 登录
     */
    @RequestMapping(value = "/login", method = POST)
    public String login(HttpServletRequest request) {

        HttpSession session = request.getSession(true);
        logger.info(String.format("Handle login request with events[id=%s,createOn=%s,lastAccessedOn=%s]", session.getId(), session.getCreationTime(), session.getLastAccessedTime()));

        String username = WebUtils.getCleanParam(request, "username");
        String password = WebUtils.getCleanParam(request, "password");

        if (Strings.isNullOrEmpty(username) || Strings.isNullOrEmpty(password)) {
            return "redirect:" + webDomain + "/login?code=" + EMPTY_INFO;
        }

        Subject subject = SecurityUtils.getSubject();

        if (subject.isAuthenticated()) {
            subject.logout();
        }

        try {

            checkCaptcha(request);
            AuthenticationToken token = createToken(request);

            subject.login(token);
            WebUser user = queryChannelService.findOne("select u from WebUser u where u.username = :username and u.role.name = 'MERCHANT' ", ImmutableMap.of("username", subject.getPrincipal()), WebUser.class);

            if (null == user) {
                throw new NullPointerException();
            }

            Securitys.activateUserSession(user);

            logApplication.eventOfMerchant(user, "登录系统", Securitys.getIp(request));

        } catch (Exception e) {

            return "redirect:" + webDomain + "/login?code=" + translateException(e);
        }

        return "redirect:" + webDomain + "/dashboard";
    }

    /**
     * 登出
     *
     * @return
     */
    @RequestMapping(value = "/logout", method = {GET, POST})
    public String logout() {

        Subject subject = SecurityUtils.getSubject();
        Securitys.unactivateUserSession();
        subject.logout();

        return "redirect:" + webDomain + "/login";
    }


    /**
     * 图形验证码校验
     */
    private void checkCaptcha(HttpServletRequest request) {
        String captchaCode = WebUtils.getCleanParam(request, "captcha");
        HttpCaptchaUtils.checkCaptcha(captchaCode, request.getSession(true));
    }


    /**
     * 创建token
     */
    private AuthenticationToken createToken(HttpServletRequest request) {
        String username = WebUtils.getCleanParam(request, "username");
        String password = WebUtils.getCleanParam(request, "password");

        String passwordAsMd5 = MD5HashUtils.asMD5(MD5HashUtils.MD5(password), username);
        String rememberMeAsString = WebUtils.getCleanParam(request, "rememberMe");
        boolean rememberMe = false;
        if (null != rememberMeAsString) {
            rememberMe = Boolean.valueOf(rememberMeAsString);
        }
        String host = request.getRemoteHost();
        return new UsernamePasswordToken(username, passwordAsMd5, rememberMe, host);
    }


    /**
     * 异常转换
     */
    private int translateException(Exception e) {

        if (e instanceof InvalidGraphicCaptchaException) {
            return INVALID_CAPTCHA_ERROR_CODE;
        }

        if (e instanceof UnknownAccountException) {
            return UNKNOWN_ACCOUT_ERROR_CODE;
        }

        if (e instanceof LockedAccountException) {
            return LOCKED_ACCOUT_ERROR_CODE;
        }

        if (e instanceof AuthenticationException) {
            return AUTHENTICATION_ERROR_CODE;
        }

        if (e instanceof NullPointerException) {
            return USER_IS_NOT_EXIST_ERROR_CODE;
        }

        logger.error("login occur exception.", e);

        return OTHER_ERROR_CODE;
    }

}
